package org.virbraligo.vboxjavaservice.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;

import org.virbraligo.vboxjavaservice.VBoxJavaService;

public class ServicePanel extends JPanel {

	private List configurations;

	private File configFile;

	private String panelName;

	private JLabel statusLabel = new JLabel();

	private Map confFields = new HashMap();

	private JTabbedPane tabPane;

	public ServicePanel(JTabbedPane tabPane, List configurations,
			File configFile) {
		this.tabPane = tabPane;
		this.configurations = configurations;
		this.configFile = configFile;
		init();
	}

	private void init() {
		GridBagLayout layout = new GridBagLayout();
		setLayout(layout);
		GridBagConstraints cons = new GridBagConstraints();
		cons.fill = GridBagConstraints.HORIZONTAL;
		cons.insets = new Insets(3, 3, 3, 3);
		for (int i = 0; i < configurations.size(); i++) {
			Config conf = (Config) configurations.get(i);
			if (conf.getLabelName().startsWith("NT Service Name")) {
				setPanelName(conf.getValue());
			}
			cons.gridx = 0;
			cons.weightx = 0;
			cons.gridy = i;
			JLabel nameLabel = new JLabel(conf.getLabelName());
			add(nameLabel, cons);
			cons.gridx = 1;
			ConfigField valueField = new ConfigField();
			cons.weightx = 1;
			valueField.setText(conf.getValue());
			add(valueField, cons);
			valueField.setToolTipText(conf.getTooltip());
			valueField.setConf(conf);
			confFields.put(conf.getWrapperConfPropertyName(), valueField);
		}
		cons.gridx = 0;
		cons.gridy++;

		cons.gridwidth = 2;
		add(statusLabel, cons);

		JLabel empty = new JLabel();
		cons.weighty = 1;
		cons.gridy++;
		add(empty, cons);

		statusLabel.setText("service not installed");
	}

	public void setConfigFile(File configFile) {
		this.configFile = configFile;
	}

	public String getPanelName() {
		return panelName;
	}

	public void setPanelName(String panelName) {
		this.panelName = panelName;
	}

	private String validateValues() {
		String result = null;
		Iterator it = confFields.values().iterator();
		while (it.hasNext()) {
			ConfigField cf = (ConfigField) it.next();
			String v = cf.getConf().getValidator().validate(cf);
			if (v != null) {
				result = v;
				break;
			}
		}
		return result;
	}

	protected void installService() {
		String valResult = validateValues();
		if (valResult != null) {
			JOptionPane.showConfirmDialog(this, valResult, "Error",
					JOptionPane.CLOSED_OPTION);
			return;
		}
		File configF = configFile;
		if (configFile == AdminFrame.DEGFAULT_CONFIG_FILE) {
			// copy to new file and override new config values
			File dest = new File(AdminFrame.CONFIG_DIR + "/wrapper.conf."
					+ panelName);
			try {
				VBoxJavaService.copy(configFile, dest);
				configF = dest;
			} catch (IOException e) {

				e.printStackTrace();
				JOptionPane.showConfirmDialog(this, "Copy config file failed, "
						+ dest.getAbsolutePath() + ", " + e.getMessage(),
						"Failed", JOptionPane.CLOSED_OPTION);
				return;
			}
		} else {
			uninstallInternal(configF);
		}
		File newConfigFile = null;
		try {
			newConfigFile = saveNewConfig(configF);
		} catch (IOException e) {
			e.printStackTrace();
			JOptionPane.showConfirmDialog(this, "Save config file failed, "
					+ configF.getAbsolutePath() + ", " + e.getMessage(),
					"Failed", JOptionPane.CLOSED_OPTION);
			return;
		}
		if (newConfigFile != null) {
			installService(newConfigFile);
			configFile = newConfigFile;
		}
	}

	private String uninstallInternal(File configF) {
		String result = "";
		try {
			result = VBoxJavaService.execute(AdminFrame.CONFIG_DIR
					+ File.separator + "wrapper.exe -r "
					+ configF.getAbsolutePath());
		} catch (Exception e) {
			e.printStackTrace();
			result = "Exception: " + e.getMessage();
		}
		return result;

	}

	private File saveNewConfig(File originalConfigFile) throws IOException {
		String serviceName = ((ConfigField) confFields
				.get("wrapper.ntservice.name")).getText().trim();
		File tmp = new File(originalConfigFile.getAbsolutePath() + ".tmp");
		RandomAccessFile raf = new RandomAccessFile(originalConfigFile, "r");
		FileOutputStream fos = new FileOutputStream(tmp);
		String s = null;

		while ((s = raf.readLine()) != null) {
			String[] split = s.split("=");
			if (split.length > 0 && confFields.containsKey(split[0].trim())) {
				String wrapperConfPropertyName = split[0].trim();
				ConfigField field = (ConfigField) confFields
						.get(wrapperConfPropertyName);
				Config conf = field.getConf();
				String value = field.getText().trim();
				if(conf.getLabelName().equals("VM Configuration Path: ")){
					value = "\""+value+"\"";
				}
				fos.write((wrapperConfPropertyName + "=" + value + "\n")
						.getBytes());
				conf.setValue(value);
			} else if (split[0].equals("wrapper.ntservice.displayname")) {
				fos.write(("wrapper.ntservice.displayname" + "=" + serviceName + "\n")
						.getBytes());
			} else {
				fos.write(s.getBytes());
				fos.write('\n');
			}
		}
		fos.flush();
		fos.close();
		raf.close();
		originalConfigFile.delete();
		File newConfigFile = new File(AdminFrame.CONFIG_DIR.getAbsolutePath()
				+ "/wrapper.conf." + serviceName);
		tmp.renameTo(newConfigFile);
		tabPane.setTitleAt(tabPane.getSelectedIndex(), serviceName);
		return newConfigFile;
	}

	private void installService(File destConfigFile) {
		String result = "";
		try {
			String cmd = AdminFrame.CONFIG_DIR.getAbsolutePath()
					+ File.separator + "wrapper.exe -i "
					+ destConfigFile.getAbsolutePath();
			System.out.println(cmd);
			result = VBoxJavaService.execute(cmd);
			result = "Result! " + result;
		} catch (Exception e) {
			e.printStackTrace();
			result = "Exception: " + e.getMessage();
		}
		JOptionPane.showConfirmDialog(this, result, "Install",
				JOptionPane.CLOSED_OPTION);
	}

	protected void uninstallService() {
		if (configFile == AdminFrame.DEGFAULT_CONFIG_FILE) {
			JOptionPane.showConfirmDialog(this, "Service not installed yet",
					"Error", JOptionPane.CLOSED_OPTION);
			return;
		} else {
			String result = uninstallInternal(configFile);
			JOptionPane.showConfirmDialog(this, result, "Uninstall",
					JOptionPane.CLOSED_OPTION);
		}
	}

}